﻿namespace Snipps.ViewModels.Pages
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows.Input;

    using MvvmFoundation.Wpf;

    using Snipps.Core;
    using Snipps.Core.Entities;
    using Snipps.Infrastructure;
    using Snipps.Infrastructure.Services;
    using Snipps.Langs;
    using Snipps.ViewModels.Filters;

    using RelayCommand = GalaSoft.MvvmLight.Command.RelayCommand;

    public class FilterViewModel : BindableBase, IHasProgrammingLangsFilter, IHasSnippetsFilter, IHasTagsFilter, IPageViewModel
    {
        public const string CurrentSnippetContentPropertyName = "CurrentSnippetContent";

        public const string IsSnippetDetailsVisiblePropertyName = "IsSnippetDetailsVisible";

        private readonly IList<IsActive> _actives;

        private readonly IList<PropertyObserver<IsActive>> _activesObservers;

        private readonly PropertyObserver<CompletionListViewModel> _selectedSnippetObserver;

        private readonly SnippetFilterViewModel _snippetFilter;

        private readonly ISnippetsDataContext _snippetsDataContext;

        private readonly ProgrammingLangFilterViewModel _programmingLangFilter;

        private readonly PropertyObserver<ProgrammingLangFilterViewModel> _programmingLangFilterObserver;

        private readonly TagFilterViewModel _tagFilter;

        private IFilterViewModel _currentFilter;

        private string _currentSnippetContent;

        private string _currentSnippetContentFast;

        private bool _isActive;

        private bool _isSnippetDetailsVisible;

        private IsActive _lastActive;

        private object _selectedItem;

        public FilterViewModel(ISnippetsDataContext snippetsDataContext, IThreadingService threadingService)
        {
            CurrentSnippetContentFast = "loading...";
            _snippetsDataContext = snippetsDataContext;

            _actives = new List<IsActive>();

            ToggleSnippetContentVisibilityCommand = new RelayCommand(OnToggleSnippetContentVisibility);

            _tagFilter = new TagFilterViewModel(_snippetsDataContext, threadingService);
            _programmingLangFilter = new ProgrammingLangFilterViewModel(_snippetsDataContext, threadingService);

            _snippetFilter = new SnippetFilterViewModel(_snippetsDataContext, _tagFilter.FilterTags, threadingService);

            _actives.Add(_snippetFilter);
            _actives.Add(_programmingLangFilter);
            _actives.Add(_tagFilter);

            _activesObservers = new List<PropertyObserver<IsActive>>();

            foreach (BindableBase active in _actives)
            {
                if (active != null)
                {
                    var activeObserver = new PropertyObserver<IsActive>(active as IsActive);
                    activeObserver.RegisterHandler(x => x.IsActive, UpdateCurrentFilter);
                    _activesObservers.Add(activeObserver);
                }
            }

            _programmingLangFilterObserver = new PropertyObserver<ProgrammingLangFilterViewModel>(_programmingLangFilter);
            _programmingLangFilterObserver.RegisterHandler(x => x.CurrentProgrammingLang, UpdateCurrentProgrammingLang);

            _selectedSnippetObserver = new PropertyObserver<CompletionListViewModel>(_snippetFilter.CompletionList);
            _selectedSnippetObserver.RegisterHandler(x => x.SelectedItem, UpdateSnippetContent);
        }

        public CompletionListViewModel CurrentCompletionList
        {
            get
            {
                return _currentFilter.CompletionList;
            }
        }

        public IFilterViewModel CurrentFilter
        {
            get
            {
                return _currentFilter;
            }

            set
            {
                SetProperty(ref _currentFilter, value, "CurrentFilter", OnCurrentFilterChanged);
            }
        }

        public ICommand ToggleSnippetContentVisibilityCommand { get; private set; }

        public string CurrentSnippetContent
        {
            get
            {
                return _currentSnippetContent;
            }

            set
            {
                SetProperty(ref _currentSnippetContent, value, CurrentSnippetContentPropertyName);
            }
        }

        public bool IsSnippetDetailsVisible
        {
            get
            {
                return _isSnippetDetailsVisible;
            }

            set
            {
                SetProperty(ref _isSnippetDetailsVisible, value, IsSnippetDetailsVisiblePropertyName);
            }
        }

        public object SelectedItem
        {
            get
            {
                return _selectedItem;
            }

            set
            {
                SetProperty(ref _selectedItem, value, "SelectedItem");
            }
        }

        public string CurrentSnippetContentFast
        {
            get
            {
                return _currentSnippetContentFast;
            }

            set
            {
                SetProperty(ref _currentSnippetContentFast, value, "CurrentSnippetContentFast");
            }
        }

        public SnippetFilterViewModel SnippetFilter
        {
            get
            {
                return _snippetFilter;
            }
        }

        public ProgrammingLangFilterViewModel ProgrammingLangFilter
        {
            get
            {
                return _programmingLangFilter;
            }
        }

        public TagFilterViewModel TagFilter
        {
            get
            {
                return _tagFilter;
            }
        }

        public string Name
        {
            get
            {
                return Lang.FilterSnippetsViewName;
            }
        }

        public bool IsActive
        {
            get
            {
                return _isActive;
            }

            set
            {
                SetProperty(ref _isActive, value, "IsActive", OnIsActiveChanged);
            }
        }

        private void UpdateCurrentProgrammingLang(ProgrammingLangFilterViewModel obj)
        {
            _snippetFilter.CurrentProgrammingLang = obj.CurrentProgrammingLang;
        }

        private void OnCurrentFilterChanged()
        {
            if (CurrentFilter != _snippetFilter)
            {
                IsSnippetDetailsVisible = false;
            }
        }

        private void OnToggleSnippetContentVisibility()
        {
            if (CurrentFilter is SnippetFilterViewModel)
            {
                IsSnippetDetailsVisible = !IsSnippetDetailsVisible;

                if (IsSnippetDetailsVisible)
                {
                    BindSnippetContent();
                }
            }
        }

        private void UpdateSnippetContent(CompletionListViewModel completionList)
        {
            if (IsSnippetDetailsVisible && completionList.SelectedItem != null)
            {
                BindSnippetContent();
            }
        }

        private void BindSnippetContent()
        {
            var currentCompletionList = CurrentFilter.CompletionList;
            var newableSelectedItem = currentCompletionList.SelectedItem as INewable;
            if (newableSelectedItem != null && !newableSelectedItem.IsNew)
            {
                if (currentCompletionList.SelectedItem is Snippet)
                {
                    var snippet = currentCompletionList.SelectedItem as Snippet;
                    var content = snippet.Content;
                    var shortContent = content;
                    if (shortContent.Length > 210)
                    {
                        shortContent = shortContent.Remove(209);
                        shortContent += Environment.NewLine;
                    }

                    CurrentSnippetContentFast = shortContent;
                    CurrentSnippetContent = content;
                }
            }
            else
            {
                CurrentSnippetContent = null;
            }
        }

        private void UpdateCurrentFilter(IsActive sActive)
        {
            if (_lastActive != null)
            {
                _lastActive.IsActive = false;
            }

            var active = _actives.FirstOrDefault(x => x.IsActive);

            if (active is IFilterViewModel)
            {
                CurrentFilter = active as IFilterViewModel;
            }

            _lastActive = active;
        }

        private void OnIsActiveChanged()
        {
            if (IsActive)
            {
                if (CurrentFilter == null)
                {
                    _snippetFilter.IsActive = true;
                }
                else
                {
                    CurrentFilter.IsActive = true;
                }
            }
            else
            {
                foreach (var active in _actives)
                {
                    active.IsActive = false;
                }
            }
        }
    }
}